package lol_stream_manager;

import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.cpp.opencv_core;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.awt.image.RasterFormatException;
import java.io.File;
import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
import com.googlecode.javacpp.Pointer;
import com.googlecode.javacv.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import java.io.FileInputStream;
import java.util.ArrayList;

public class LOL_Stream_Manager {
    public static Properties config = new Properties();
    
    public static List<String[]>[] results;
    
    public static void main(String[] args) throws Exception {
//        config.load(new FileInputStream("settings.txt"));
//
//        results = (List<String[]>[]) new List[4];
//        for(int i=0 ; i<4 ; i++)
//            results[i] = new ArrayList<>();
//
////        BufferedImage image = ImageIO.read(new File("bug.jpg"));
////        BufferedImage tmpimage = image.getSubimage(0, image.getHeight()-120, 119, 119);
////        System.out.println( "Bugtest -> " + ImageFinder.bestImage( "tsm_theoddone", tmpimage ) );
////        if(true) return;
//        
//        String[] channels = {"tsm_theoddone", "tsm_chaox", "tsm_dyrus", "phantoml0rd", "nhatn",
//                             "tsm_xpecial", "therainman", "bestrivenna", "muffinqt", /*"chu8", */"zekent",
//                             "wingsofdeath", "salce", "lolsooner"
//        };
//
//        for(String channel : channels){
//            characterFinder.characterFinder(channel);
//            System.out.println("");
//        }
//        
//        String[][] ownedChannels = {
//            {"GuardsmanBob", "34046"},
//            {"ocelote", "2721"},
//            {"SaintVicious", "340254"},
//            {"HotshotGG", "13574"},
//            {"Elementz", "340257"},
//            {"Krepo", "194947"},
////            {"CrsCop", "340245"},
//        };
//        
//        for( String[] channel : ownedChannels ){
//            characterFinder.characterFinderOwned( channel[0], channel[1] );
//            System.out.println("");
//        }
//        
//        System.out.println("Error: ");
//        System.out.println("----------------");
//        for( String[] s: results[3])
//            System.out.println( s[0] + ": " + s[1] );
//
//        System.out.println("\nOffline streams: ");
//        System.out.println("----------------");
//        for( String[] s: results[0])
//            System.out.println( s[0] );
//        
//        System.out.println("\nStreams not playing: ");
//        System.out.println("----------------");
//        for( String[] s: results[1])
//            System.out.println( s[0] );
//
//        System.out.println("\nStreams playing: ");
//        System.out.println("----------------");
//        for( String[] s: results[2])
//            System.out.println( s[0] + ": " + s[1] );

        
//        edgeDetectionTest(  "vayne_test2.png" );
//        edgeDetectionTest(  "vayne_test3.png" );
//        edgeDetectionTest(  "ezreal_test.png" );
//        edgeDetectionTest(  "ezreal_test2.png" );
//        edgeDetectionTest(  "tsm_chaox.jpg" );
//        edgeDetectionTest(  "muffinqt.jpg" );
//        edgeDetectionTest(  "gragas.png" );
//        edgeDetectionTest(  "tsm_xpecial.jpg" );
//        sobelDetectionTest(  "edges\\score.jpg" );
        
        fullSmartOffsetTest( 40, true );
        
//        fullHoughLineTest( 45 );
    }

    public static void fullSmartOffsetTest( int threshold, boolean isDebug ) throws Exception {
        File d = new File("games");
        File[] files = d.listFiles();
        for( File f : files )
            if( f.isDirectory() ){
                File[] subFiles = f.listFiles();
                for( File subFile : subFiles )
                    subFile.delete();
            }
        for( File f : files )
            if( f.isFile() ){
                BufferedImage tmp = getSmartOffset2(  f.getName(), threshold );
                if( tmp != null){
                    ImageIO.write( tmp, "png", new File("games\\cuts\\" + f.getName() + ".png"));
                }
                if( isDebug )
                    ImageIO.write( sobelDetectionTest( f.toString(), threshold), "png", new File("games\\debug\\" + f.getName() + ".png"));
            }
    }
    
    public static void edgeDetectionTest( String file ) throws Exception {
        CannyEdgeDetector detector = new CannyEdgeDetector();
        detector.setLowThreshold(0.01f); 
        detector.setHighThreshold(0.02f);
        BufferedImage image = ImageIO.read(new File(file));
        detector.setSourceImage(image);
        detector.process();
        BufferedImage edgeImage = detector.getEdgesImage();
        ImageIO.write(edgeImage, "png", new File(file + ".png"));
    }
    
    public static BufferedImage sobelDetectionTest( String file, int threshold ) throws Exception {
        BufferedImage image = ImageIO.read(new File(file));
        image = image.getSubimage(0, image.getHeight()-120, 100, 115);
        SobelEdgeDetector detector = new SobelEdgeDetector();
        detector.init( image );
        detector.setThreshold( threshold );
        BufferedImage edgeImage = detector.process();
        return edgeImage;
    }
    
    public static BufferedImage getSmartOffset( String file, int threshold ) throws Exception {
        BufferedImage fullImage = ImageIO.read(new File(file));
        BufferedImage image = fullImage.getSubimage(0, fullImage.getHeight()-120, 100, 115);
        SobelEdgeDetector detector = new SobelEdgeDetector();
        detector.init( image );
        detector.setThreshold(threshold);
        BufferedImage edgeImage = detector.process();
//        int[] unlinkedMaxLines = getMaxUnlinkedLines(detector.bwEdgeRaster);
//        for(int i=0 ; i<unlinkedMaxLines.length ; i++)
//            System.out.println(i + " -> " + unlinkedMaxLines[i]);
//        detector.bwEdgeRaster = joinLines( detector.bwEdgeRaster, 1 );
        booleanToImage( detector.bwEdgeRaster, file + ".png");
        int[][] maxLines = getMaxLines(detector.bwEdgeRaster);
        int[] sPos = new int[3];    // As [x, y, line length]
        int firstLine[] = new int[] {0, 0};
        for(int i=0 ; i<maxLines.length ; i++)
            if( maxLines[i][0] > 30 ){
                firstLine = new int[] {i, maxLines[i][0]};
                break;
            }
        for(int i=firstLine[0]+5 ; i<maxLines.length ; i++)
            if( maxLines[i][0] > 30 && maxLines[i][0] < firstLine[1] - 10 ){
                sPos[0] = maxLines[i][1];
                sPos[1] = i;
                sPos[2] = maxLines[i][0];
                break;
            }
        int errPosX = 0;
        int errPosY = 2;
        BufferedImage cutImage = null;
        try {
            cutImage = image.getSubimage(sPos[0] - errPosY, sPos[1] - errPosX, sPos[2] + 2*errPosY, sPos[2] + 2*errPosY);
        } catch( RasterFormatException e ){
            System.out.println( file + " -> Error");
        }
        return cutImage;
    }
    
    public static BufferedImage getSmartOffset2( String file, int threshold ) throws Exception {
        BufferedImage fullImage = ImageIO.read( new File( "games\\" + file ) );
        BufferedImage image = fullImage.getSubimage(0, fullImage.getHeight()-120, 100, 115);
        SobelEdgeDetector detector = new SobelEdgeDetector();
        detector.init( image );
        detector.setThreshold(threshold);
        BufferedImage edgeImage = detector.process();
        detector.bwEdgeRaster = joinLines( detector.bwEdgeRaster, 1 );
        booleanToImage( detector.bwEdgeRaster, "games\\joinpixels\\" + file + ".png");
        
        int[] unlinkedMaxLines = getMaxUnlinkedLines(detector.bwEdgeRaster);
        int yMaxOffset = 0;
        while( unlinkedMaxLines[yMaxOffset] < 40 )
            yMaxOffset++;
//        System.out.println(yMaxOffset);

        int minToFind = ((115-yMaxOffset)*2)/3;
        int verLine = 99;
        while( verLine > 0 && getMaxVerLine(detector.bwEdgeRaster, verLine)[0] < minToFind )
            verLine--;
        
        int[] sPos = getMaxVerLine(detector.bwEdgeRaster, verLine);
//        System.out.println(verLine + ": " + sPos[0] + " @ " + sPos[1]);
        
        int errPos = 2;
        BufferedImage cutImage = null;
        try {
            cutImage = image.getSubimage(verLine - sPos[0] - 2*errPos, sPos[1] - errPos, sPos[0] + 2*errPos, sPos[0] + 2*errPos);
        } catch( RasterFormatException e ){
            System.out.println( file + " -> Error");
        }
        return cutImage;
    }
    
    public static int[][] getMaxVerLines( boolean[][] raster ){
        int[][] maxLines = new int[raster[0].length][2];
        for(int i=0 ; i<raster[0].length ; i++)
            maxLines[i] = getMaxVerLine( raster, i );
        return maxLines;
    }
    
    public static int[] getMaxVerLine( boolean[][] raster, int line ){
        int maxLine = 0;
        int maxPos = 0;
        int currentLine = 0;
        int currentPos = 0;
        for( int i=0 ; i<raster.length ; i++ ){
            if( raster[i][line] ){
                if( currentLine == 0)
                    currentPos = i;
                currentLine++;
            } else {
                if( currentLine > maxLine ){
                    maxLine = currentLine;
                    maxPos = currentPos;
                }
                currentLine = 0;
                currentPos = 0;
            }
        }
        return new int[] {maxLine, maxPos};
    }
    
    public static int[][] getMaxLines( boolean[][] raster ){
        int[][] maxLines = new int[raster.length][2];
        for(int i=0 ; i<raster.length ; i++)
            maxLines[i] = getMaxLine( raster[i] );
        return maxLines;
    }
    
    public static int[] getMaxLine( boolean[] line ){
        int maxLine = 0;
        int maxPos = 0;
        int currentLine = 0;
        int currentPos = 0;
        for( int i=0 ; i<line.length ; i++ ){
            if( line[i] ){
                if( currentLine == 0)
                    currentPos = i;
                currentLine++;
            } else {
                if( currentLine > maxLine ){
                    maxLine = currentLine;
                    maxPos = currentPos;
                }
                currentLine = 0;
                currentPos = 0;
            }
        }
        return new int[] {maxLine, maxPos};
    }
    
    public static int[] getMaxUnlinkedLines( boolean[][] raster ){
        int[] maxLines = new int[raster.length];
        for( int i=0 ; i<raster.length ; i++ )
            for( int j=0 ; j<raster[0].length ; j++ )
                if( raster[i][j] )
                    maxLines[i]++;
        return maxLines;
    }
    
    public static boolean[][] joinLines( boolean[][] raster, int threshold ){
        boolean[][] res = new boolean[raster.length][raster[0].length];
        for(int i=0 ; i<raster.length ; i++)
            for(int j=0 ; j<raster[0].length ; j++){
                boolean isColored = false;
                for(int k=Math.max(0, i-threshold) ; k<Math.min(raster.length, i+threshold) ; k++ )
                    for(int l=Math.max(0, j-threshold) ; l<Math.min(raster[0].length, j+threshold) ; l++)
                        if( raster[k][l] )
                            isColored = true;
                res[i][j] = isColored;
            }
        return res;
    }
    
    public static void booleanToImage( boolean[][] raster, String file ) throws Exception {
        BufferedImage image = new BufferedImage(raster[0].length, raster.length, BufferedImage.TYPE_INT_RGB);
        for(int i=0 ; i<raster.length ; i++)
            for(int j=0 ; j<raster[0].length ; j++)
                image.setRGB(j, i, ( raster[i][j] ? 16777215 : 0 ));
        ImageIO.write(image, "png", new File(file) );
    }
    
    public static void houghLineTest( String file, int threshold ) throws Exception {
        BufferedImage fullImage = ImageIO.read(new File(file));
        BufferedImage image = fullImage.getSubimage(0, fullImage.getHeight()-120, 119, 119);
        ImageIO.write(image, "png", new File(file + "_redim.png"));
        houghLineDetector( file + "_redim.png", file + "_hough.png", threshold);
    }
    
    public static void houghLineDetector( String file, String fToSave, int threshold ){
        opencv_core.IplImage src = cvLoadImage( file , 0 );
        opencv_core.IplImage dst = cvCreateImage(cvGetSize(src), src.depth(), 1);
        opencv_core.IplImage colorDst = cvCreateImage(cvGetSize(src), src.depth(), 3);
        opencv_core.CvMemStorage storage = cvCreateMemStorage(0);

        cvCanny(src, dst, 50, 200, 3);
        cvCvtColor(dst, colorDst, CV_GRAY2BGR);

        opencv_core.CvSeq lines = cvHoughLines2(dst, storage, CV_HOUGH_STANDARD, 1, Math.PI / 180, threshold, 0, 0);

        for (int i = 0; i < lines.total(); i++) {
            CvPoint2D32f point = new CvPoint2D32f(cvGetSeqElem(lines, i));

            float rho=point.x();
            float theta=point.y();

            double a = Math.cos((double) theta), b = Math.sin((double) theta);
            double x0 = a * rho, y0 = b * rho;
            CvPoint pt1 = new CvPoint((int) Math.round(x0 + 1000 * (-b)), (int) Math.round(y0 + 1000 * (a)));
            CvPoint pt2 = new CvPoint((int) Math.round(x0 - 1000 * (-b)), (int) Math.round(y0 - 1000 * (a)));
            System.out.println("Line spotted: ");
            System.out.println("\t rho= " + rho);
            System.out.println("\t theta= " + theta);
            if( theta < 0.1 || (theta > 1.54 && theta < 1.63) || theta > 3.1 )
                cvLine(colorDst, pt1, pt2, CV_RGB(255, 0, 0), 1, CV_AA, 0);
        }
        
        cvSaveImage(fToSave, colorDst);
    }
    
    public static void fullHoughLineTest( int threshold ) throws Exception {
        File d = new File("games");
        File[] files = d.listFiles();
        for( File f : files )
            if( f.isDirectory() ){
                File[] subFiles = f.listFiles();
                for( File subFile : subFiles )
                    subFile.delete();
            }
        for( File f : files )
            if( f.isFile() ){
                BufferedImage fullImage = ImageIO.read( f );
                BufferedImage image = fullImage.getSubimage(0, fullImage.getHeight()-120, 100, 119);
                File redimFile = new File(f + "_redim.png");
                ImageIO.write(image, "png", redimFile);
                houghLineDetector( f + "_redim.png", "games\\hough\\" + f.getName(), threshold);
                redimFile.delete();
            }
    }
}
